package net.ncraft.mc.easyframework.sql.transactional;

import net.ncraft.mc.easyframework.aop.anno.Aspect;
import net.ncraft.mc.easyframework.aop.anno.Pointcut;
import net.ncraft.mc.easyframework.aop.core.JoinPoint;
import net.ncraft.mc.easyframework.context.anno.Autowired;
import net.ncraft.mc.easyframework.context.anno.Component;
import net.ncraft.mc.easyframework.sql.anno.Transactional;
import org.apache.ibatis.session.SqlSessionManager;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

@Aspect
@Component
public class TransactionalAspect {

    @Autowired
    private TransactionFactory transactionFactory;

    @Autowired
    private SqlSessionManager sqlSessionManager;

    @Pointcut(Transactional.class)
    public Object transactional(JoinPoint joinPoint) throws Throwable {
        sqlSessionManager.startManagedSession();
        Class<? extends Exception> exception = joinPoint.getOriginalMethod().getAnnotation(Transactional.class).value();
        Transaction transaction = transactionFactory.newTransaction(sqlSessionManager.getConnection());
        try {
            Object result = joinPoint.proceed();
            transaction.commit();
            return result;
        } catch (Throwable throwable) {
            if (exception.isInstance(throwable)) {
                transaction.rollback();
                throw throwable;
            }
        }
        throw new RuntimeException("transactional error");
    }

}
